package com.wlanauth.web.action.fileProcessor;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import com.wlanauth.domain.manage.Operator;
import com.wlanauth.domain.manage.UploadFileLog;
import com.wlanauth.domain.manage.User;
import com.wlanauth.domain.manage.UserUploadFile;
import com.wlanauth.service.manage.UploadFileLogService;
import com.wlanauth.service.manage.UserService;
import com.wlanauth.service.manage.UserUploadFileService;
import com.wlanauth.web.core.SystemConstants;
import com.wlanauth.web.core.file.FileProcessor;
import com.wlanauth.web.core.file.FileProcessorContext;
import com.wlanauth.web.core.file.FileProcessorException;
import com.wlanauth.web.core.file.FileUploadResult;

/**
 * 用户文件上传处理
 * @author zz
 * @date 2012-5-26
 * @email charles.zz.life@gmail.com
 */
public class UserFileProcessor implements FileProcessor {

	private static Logger logger = Logger.getLogger(UserFileProcessor.class);
	
	private UserService userService ;//用户服务接口
	
	private UserUploadFileService uploadFileService;//文件上传
	
	private UploadFileLogService uploadFileLogService ;//上传日志

	private static List<SimpleDateFormat> dateFormats = new ArrayList<SimpleDateFormat>();
	static {
		dateFormats.add(new SimpleDateFormat("yyyy/MM/dd"));
		dateFormats.add(new SimpleDateFormat("yyyy-MM-dd"));
	}
	
	private String getFileExten(String filename) {
		return  filename.substring(filename.lastIndexOf('.')).toLowerCase();
	}
	
	public FileUploadResult process(FileProcessorContext ctx) throws FileProcessorException {
		List<UserUploadFile> list = new ArrayList<UserUploadFile>();
		List<File> files = ctx.getFiles();
		
		for(File file:files){
			UserUploadFile upload = processFile(file,ctx);
			upload.getOperator().setRole(null);
			list.add(upload);
		}
		FileUploadResult result = new FileUploadResult();
		
		result.setSuccess(true);
		result.setProcessResult(list);
		return result;
	}
	private UserUploadFile processFile(File file,FileProcessorContext ctx) throws FileProcessorException{
		UserUploadFile upload = null;
		String type = ctx.getAction().getRequest().getParameter("fileType");
		logger.info("处理文件:" + file.getAbsolutePath()+ ",指定类型:" + type);
		FileInputStream in = null;
		
		try {
			long startTime = System.currentTimeMillis();
			Operator oper = (Operator) ctx.getAction().getRequest().getSession().getAttribute(SystemConstants.SESSION_OPER_KEY);
			//保存
			upload = new UserUploadFile();
			upload.setDescription("用户Excel");
			upload.setName(file.getName());
			upload.setLength(file.length());
			upload.setOperator(oper);
			upload.setPath(file.getPath());
			upload.setUploadTime(Calendar.getInstance().getTime());
			
			upload.setType(getFileExten(file.getName()));
			upload.setBatchId(BatchIDGenerator.id());
			//upload.setTotalNum(-1);
			//upload.setSuccessNum(-1);
			uploadFileService.save(upload);
			
			in = new FileInputStream(file);
			if("excel".equals(type)||getFileExten(file.getName()).equals(".xls")){
				processExcel(in, upload,file,ctx);
			} else if ("txt".equals(type)||getFileExten(file.getName()).equals(".txt")){
				//处理文件本件
				processTxt(in,upload,file,ctx);
			} else {
				logger.warn("非系统认可文件，不予业务处理[file:"+file.getName()+"]");
			}
			logger.info("成功处理文件["+file.getName()+"],耗时:"+(System.currentTimeMillis()-startTime)+" ms");
		} catch (Exception ex) {
			throw new FileProcessorException("处理异常:"+ex.getMessage(),ex);
		} finally {
			if (in != null) {
				try { in.close();} catch (IOException e) {}
			}
		}
		return upload;

	}
	/**
	 *  * 读取行至用户对象 
	 * 卡号 PUK码 绑定的IP 有效期限 总流量（MB） 总金额（元）
	 *  8986011132535006120  23.32.654.123 2012-12-12 6000 600
	 * @param in
	 * @param upload
	 * @param file
	 * @param ctx
	 */
	private void processTxt(FileInputStream in,UserUploadFile upload, File file,
			FileProcessorContext ctx) throws Exception {
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String s = null;
		int lineNum = 0,successNum = 0;
		Calendar c = Calendar.getInstance();//同一时间激活
		while((s = reader.readLine())!= null){
			try {
				String[] str = s.split("\\|");
				if(str.length<6){
					throw new Exception("格式与期望不符[格式:卡号|PUK码|绑定IP|有效期(yyyy-MM-dd)|总流量(M)|总金额]");
				}
				User user = new User();
				user.setUsername(str[0]);
				user.setPuk(str[1]);
				user.setBindIP(str[2]);
				
				user.setExpiredTime(parseDate(str[3]));
				user.setMaxOctets(Float.valueOf(str[4]));
				user.setActualFee(Double.parseDouble(str[5]));
				user.setActiveTime(c.getTime());
				user.setJoinTime(c.getTime());
				this.saveUser(user,upload.getBatchId());
				successNum++;
			} catch (Exception e){
				logger.warn("行处理异常:"+e.getMessage(),e);
				UploadFileLog log = new UploadFileLog();
				log.setLineNum(lineNum);
				log.setOrginalValue(s);
				log.setMsg(e.getMessage());
				log.setDescription("行处理异常:"+e.getMessage());
				log.setType(UploadFileLog.TYPE_WARN);
				log.setCreateTime(new Date());
				log.setUploadFileId(upload.getId());
				this.uploadFileLogService.save(log);
			}
			lineNum++;
		}
		upload.setTotalNum(lineNum);
		upload.setSuccessNum(successNum);
		reader.close();
	}
	
	private Date parseDate(String str){
		Date d = null;
		for(SimpleDateFormat df:dateFormats){
			try {
				d = df.parse(str);
				return d;
			} catch (Exception e){
				
			}
		}
		if(d == null){
			throw new RuntimeException("日期格式为yyyy-MM-dd或yyyy/MM/dd[实际:"+str+"]");
		}
		return d;
	}
	/**
	 * 处理Excel表格
	 * @param in
	 * @param ctx
	 * @throws Exception
	 */
	private void processExcel(FileInputStream in,UserUploadFile upload, File file,FileProcessorContext ctx) throws Exception {
		
		
		HSSFWorkbook workbook = new HSSFWorkbook(in);
		int sheetCount = workbook.getNumberOfSheets();
		logger.debug("工作簿数:" + sheetCount);
		int total =0,successNum = 0;
		Calendar c = Calendar.getInstance();//同一时间激活
		for (int i = 0; i < sheetCount; i++) {
			try {
				String sheetname = workbook.getSheetName(i);
				HSSFSheet sheet = workbook.getSheet(sheetname);
				// HSSFRow row = sheet.getRow(0);//第一行忽略处理
				int rowCount = sheet.getPhysicalNumberOfRows();// 获取行数
				for (int j = 1; j < rowCount; j++) { // 遍历行
					// 每行处理失败不要影响下一行的处理
					try {
						HSSFRow row = sheet.getRow(j);
						User user = readHSSFRowToUser(row);
						if(user == null){
							continue ;
						}
						user.setActiveTime(c.getTime());
						user.setJoinTime(c.getTime());
						saveUser(user,upload.getBatchId());
						successNum++;
					} catch (Exception e){
						logger.warn("行处理异常:[sheetName:"+sheetname+",sheetIndex:"+i+",rowIndex:"+j+"]",e);
						UploadFileLog log = new UploadFileLog();
						log.setLineNum(j);
						log.setMsg(e.getMessage());
						log.setDescription("行处理异常:[sheetName:"+sheetname+",sheetIndex:"+i+",rowIndex:"+j+"]");
						log.setType(UploadFileLog.TYPE_WARN);
						log.setCreateTime(new Date());
						log.setUploadFileId(upload.getId());
						this.uploadFileLogService.save(log);
					}
					total++;
				}
			} catch (Exception e){
				logger.error("工作簿处理异常[sheetIndex:"+i+"]",e);
				
				UploadFileLog log = new UploadFileLog();
				log.setLineNum(-1);
				log.setMsg(e.getMessage());
				log.setDescription("工作簿处理异常:[sheetIndex:"+i+"");
				log.setType(UploadFileLog.TYPE_ERROR);
				log.setCreateTime(new Date());
				log.setUploadFileId(upload.getId());
				this.uploadFileLogService.save(log);
			}
			
		}
		upload.setTotalNum(total);
		upload.setSuccessNum(successNum);
		uploadFileService.update(upload);
	}
	
	private void saveUser(User entity,String batchId) {
		if(StringUtils.isBlank(entity.getBindIP())){
			throw new RuntimeException("绑定IP不能为空");
		}
		if(StringUtils.isBlank(entity.getUsername())){
			throw new RuntimeException("用户名不能为空");
		}
		User temp = userService.getByBindIP(entity.getBindIP());
		
		if(temp != null){
			throw new RuntimeException("该IP已被绑定,IP:"+entity.getBindIP());
		}
		temp = userService.getByUsername(entity.getUsername());
		if(temp != null){
			throw new RuntimeException("该用户已存在,用户名:"+entity.getUsername());
		}
		if(StringUtils.isBlank(entity.getPuk())){
			entity.setPuk(this.genPuk(entity.getUsername()));
		}
		entity.setPassword(entity.getPuk());//初始密码与PUK相同
		entity.setUserType(User.TYPE_DEFAULT);
		entity.setStatus(User.STATUS_ENABLED);
		entity.setBatchId(batchId);
		
		//取得当前计费比率(单位kb/元)
		//entity.setRatedFee(RadiusUtils.getFee(entity.getMaxOctets()));
		//if(entity.getActualFee() == null){
		
		entity.setRatedFee(entity.getActualFee());
		//}
		//加密密码
		
		entity.setPassword(com.wlanauth.core.util.MD5Util.encode(entity.getPassword()));
	
		userService.save(entity);
	}

	private Object readHSSFCellToObject(HSSFCell cell) {
		Object value = "";
		switch (cell.getCellType()) {
		case HSSFCell.CELL_TYPE_STRING:
			value = cell.getRichStringCellValue();
			break;
		case HSSFCell.CELL_TYPE_BOOLEAN:
			value = cell.getBooleanCellValue();
			break;
		case HSSFCell.CELL_TYPE_NUMERIC:
			if (HSSFDateUtil.isCellDateFormatted(cell)) {
				value = HSSFDateUtil.getJavaDate(cell.getNumericCellValue());
			} else {
				value = cell.getNumericCellValue();
			}
			break;
		case HSSFCell.CELL_TYPE_FORMULA: // 来自网络，未测试
			value = cell.getNumericCellValue();
			if ("NAN".equals(value.toString())) {
				value = cell.getRichStringCellValue();
			}
			break;
		default:
			value = cell.getRichStringCellValue();
			
			
		}

		return value;
	}

	/**
	 * 读取行至用户对象 
	 * 卡号 PUK码 绑定的IP 有效期限 总流量（MB） 总金额（元）
	 *  8986011132535006120  23.32.654.123 2012-12-12 6000 600
	 * 
	 * @param row
	 * @return
	 */
	private User readHSSFRowToUser(HSSFRow row) {
		User user = new User();
		int cellCount = row.getLastCellNum();
		for (int i = 0; i < cellCount; i++) {// 遍历列
			Object obj = readHSSFCellToObject(row.getCell(i));
			switch (i) {
			case 0:
				user.setUsername(obj.toString());
				break;
			case 1:
				user.setPuk(obj.toString());
				
				break;
			case 2:
				if(StringUtils.isBlank(user.getUsername())&&StringUtils.isBlank(obj.toString())){ //IP和用户同时为空
					return null;
				}
				user.setBindIP(obj.toString());
				break;
			case 3:
				if(obj instanceof Date){
					user.setExpiredTime((Date) obj);
				} else {
					user.setExpiredTime(parseDate(obj.toString()));
				}
				break;
			case 4:
				Double d = Double.parseDouble(obj.toString());
				user.setMaxOctets(d.floatValue());
				break;
			case 5:
				user.setActualFee(Double.parseDouble(obj.toString()));
				break;
			}
		}
		return user;
	}
	/**
	 * 产生密码
	 * @param username
	 * @return
	 */
	private String genPuk(String username) {
		if(username == null ) return null;
		if(username.length()<6) return StringUtils.leftPad(username, 6);
		return username.substring(username.length()-6);
	}
	
	
	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	

	
	public void setUploadFileLogService(UploadFileLogService uploadFileLogService) {
		this.uploadFileLogService = uploadFileLogService;
	}

	public void setUploadFileService(UserUploadFileService uploadFileService) {
		this.uploadFileService = uploadFileService;
	}
	
	/**
	 * 批次生成
	 * @author zz
	 * @date 2012-5-28
	 * @email charles.zz.life@gmail.com
	 */
	private static class BatchIDGenerator{
		static int hour = -1;
		static int seq = 0;
		static SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmm");
		static String id(){
			Calendar c = Calendar.getInstance();
			int  nowHour = c.get(Calendar.HOUR_OF_DAY);
			if(hour!=nowHour){
				seq = 0;
			}
			hour = nowHour;
			
			return df.format(c.getTime())+StringUtils.leftPad(""+(++seq), 3,'0');
		}
	}
}
